package org.jsola.hr.service.impl;

import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IInstitutionDAO;
import org.jsola.hr.dto.InstitutionAddDTO;
import org.jsola.hr.dto.InstitutionUpdateDTO;
import org.jsola.hr.entity.EmpPaperContractDO;
import org.jsola.hr.entity.InstitutionDO;
import org.jsola.hr.entity.InstitutionTypeDO;
import org.jsola.hr.query.InstitutionQuery;
import org.jsola.hr.service.IInstitutionService;
import org.jsola.hr.service.IInstitutionTypeService;
import org.jsola.hr.vo.InstitutionListVO;
import org.jsola.hr.vo.InstitutionVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 制度
 *
 * @author zhr
 */
@Service("hrInstitutionServiceImpl")
public class InstitutionServiceImpl implements IInstitutionService {

    @Autowired
    private IInstitutionDAO institutionDAO;

    @Autowired
    @Lazy
    private IInstitutionTypeService institutionTypeService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public InstitutionVO save(InstitutionAddDTO institutionAddDTO, TokenUser tokenUser) {
        ParamException.notNull(institutionAddDTO.getInstitutionTypeId(), "制度分类不能为空");
        InstitutionTypeDO institutionTypeDO = institutionTypeService
                .selectDOById(institutionAddDTO.getInstitutionTypeId(), tokenUser.getSiteId());
        ParamException.notNull(institutionTypeDO, "制度分类信息有误，请刷新后再试");
        ParamException.isTrue(institutionTypeDO.getLevel() == 2, "制度仅允许在二级分类下添加");
        // 转DO
        InstitutionDO institutionDO = institutionAddDTO.to(InstitutionDO.class);
        // 查询同名制度
        List<InstitutionDO> institutionDOList = selectByCompanyIdAndTitle(institutionDO.getCompanyId(), institutionDO
                .getInstitutionTitle(), tokenUser.getSiteId());
        ParamException.isTrue(CollectionUtils.isEmpty(institutionDOList), "该名称已存在，无法创建");
        // 默认开启
        if (institutionDO.getIsOpen() == null) {
            institutionDO.setIsOpen(Boolean.TRUE);
        }
        // 保存
        institutionDO = save(institutionDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 如果新建制度为开启状态 则需要关闭其他制度
        if (institutionDO.getIsOpen()) {
            closeOtherInstitution(institutionDO.getId(), tokenUser);
        }
        return institutionDO.to(InstitutionVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(InstitutionUpdateDTO institutionUpdateDTO, TokenUser tokenUser) {
        ParamException.notNull(institutionUpdateDTO.getInstitutionTypeId(), "制度分类不能为空");
        InstitutionTypeDO institutionTypeDO = institutionTypeService
                .selectDOById(institutionUpdateDTO.getInstitutionTypeId(), tokenUser.getSiteId());
        ParamException.notNull(institutionTypeDO, "制度分类信息有误，请刷新后再试");
        ParamException.isTrue(institutionTypeDO.getLevel() == 2, "制度仅允许在二级分类下修改");
        //转DO
        InstitutionDO institutionDO = institutionUpdateDTO.to(InstitutionDO.class);
        // 查询同名制度
        List<InstitutionDO> institutionDOList = selectByCompanyIdAndTitle(institutionDO.getCompanyId(), institutionDO
                .getInstitutionTitle(), tokenUser.getSiteId());
        // 跳过当前修改制度
        institutionDOList = institutionDOList.parallelStream().filter(institution
                -> !institution.getId().equals(institutionUpdateDTO.getId())).collect(Collectors.toList());
        ParamException.isTrue(CollectionUtils.isEmpty(institutionDOList), "该名称已存在，无法修改");
        //根据主键更新，只更新非null值
        int updateByIdSelective = updateByIdSelective(institutionDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 如果修改后为开启状态 则需要关闭其他制度
        if (institutionUpdateDTO.getIsOpen() != null && institutionUpdateDTO.getIsOpen()) {
            closeOtherInstitution(institutionDO.getId(), tokenUser);
        }
        return updateByIdSelective;
    }

    @Override
    public int openInstitution(String institutionId, TokenUser tokenUser) {
        InstitutionDO institutionDO = new InstitutionDO();
        institutionDO.setId(institutionId);
        institutionDO.setIsOpen(Boolean.TRUE);
        int updateByIdSelective = updateByIdSelective(institutionDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 关闭其他制度
        closeOtherInstitution(institutionId, tokenUser);
        return updateByIdSelective;
    }

    @Override
    public int closeInstitution(String institutionId, TokenUser tokenUser) {
        InstitutionDO institutionDO = new InstitutionDO();
        institutionDO.setId(institutionId);
        institutionDO.setIsOpen(Boolean.FALSE);
        return updateByIdSelective(institutionDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    /**
     * 关闭其他制度
     *
     * @param institutionId 开启的制度
     * @param tokenUser     登录用户
     */
    private void closeOtherInstitution(String institutionId, TokenUser tokenUser) {
        InstitutionDO institutionDO = selectDOById(institutionId, tokenUser.getSiteId());
        ParamException.notNull(institutionDO, "制度不存在，请刷新后重试");
        // 查询该分类下所有制度
        List<InstitutionDO> institutionDOList = selectByTypeIdAndCompanyId(institutionDO.getInstitutionTypeId()
                , institutionDO.getCompanyId(), tokenUser.getSiteId());
        // 关闭其他制度
        for (InstitutionDO instanceDO : institutionDOList) {
            // 跳过当前制度
            if (institutionId.equals(instanceDO.getId())) {
                continue;
            }
            // 只有开启的制度受到影响
            if (instanceDO.getIsOpen() != null && instanceDO.getIsOpen()) {
                instanceDO.setIsOpen(Boolean.FALSE);
                updateByIdSelective(instanceDO, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... institutionIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) institutionIds);
    }


    @Override
    public InstitutionVO selectById(String institutionId, String siteId) {
        InstitutionDO institutionDO = selectDOById(institutionId, siteId);
        if (institutionDO == null) {
            return null;
        }
        return institutionDO.to(InstitutionVO.class);
    }

    @Override
    public List<InstitutionListVO> select(InstitutionQuery institutionQuery, String siteId) {
        List<InstitutionDO> institutionDOList = selectDO(institutionQuery, siteId);
        if (CollectionUtils.isEmpty(institutionDOList)) {
            return institutionDOList == null ? null : new ArrayList<>();
        }
        return institutionDOList.stream()
                .map(institutionDO -> institutionDO.to(InstitutionListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(InstitutionQuery institutionQuery, String siteId) {
        Example example = buildExample(institutionQuery, siteId);
        return institutionDAO.selectCountByExample(example);
    }

    @Override
    public Page<InstitutionListVO> selectPage(InstitutionQuery institutionQuery, String siteId) {
        Example example = buildExample(institutionQuery, siteId);
        Page<InstitutionDO> page = institutionDAO.selectPageByExample(example,
                institutionQuery.getPageNo(),
                institutionQuery.getPageSize());

        return page.to(InstitutionListVO.class);
    }

    @Override
    public InstitutionDO selectDOById(String institutionId, String siteId) {
        return listById(institutionId, siteId);
    }

    @Override
    public List<InstitutionDO> selectDO(InstitutionQuery institutionQuery, String siteId) {
        Example example = buildExample(institutionQuery, siteId);
        return institutionDAO.selectByExample(example);
    }

    @Override
    public List<InstitutionDO> selectByTypeIdAndCompanyId(String institutionTypeId
            , String companyId, String siteId) {
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("institutionTypeId", institutionTypeId);
        return institutionDAO.selectByExample(example);
    }

    @Override
    public List<InstitutionDO> selectByTypeIdsAndCompanyId(List<String> institutionTypeIds, String companyId, String siteId) {
        ParamException.notNull(companyId, "用工单位Id不能为空");
        if (CollectionUtils.isEmpty(institutionTypeIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId)
                .andIn("institutionTypeId", institutionTypeIds);
        return institutionDAO.selectByExample(example);
    }

    @Override
    public List<InstitutionDO> selectByTypeIds(List<String> institutionTypeIds, String siteId) {
        if (CollectionUtils.isEmpty(institutionTypeIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("institutionTypeId", institutionTypeIds);
        return institutionDAO.selectByExample(example);
    }

    @Override
    public List<InstitutionListVO> selectOpenByCompanyId(String companyId, String siteId) {
        ParamException.notNull(companyId, "用工单位Id不能为空");
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("isOpen", true);
        List<InstitutionDO> institutionDOList = institutionDAO.selectByExample(example);
        // 二级分类
        List<InstitutionTypeDO> institutionTypeDOList = institutionTypeService.selectDOByIds(institutionDOList
                .parallelStream().map(InstitutionDO::getInstitutionTypeId).distinct().collect(Collectors.toList()), siteId);
        Map<String, InstitutionTypeDO> institutionTypeIdDOMap2 = institutionTypeDOList.parallelStream()
                .collect(Collectors.toMap(BaseDO::getId, v -> v));
        // 一级分类
        List<InstitutionTypeDO> institutionTypeList = institutionTypeService.selectDOByIds(institutionTypeDOList
                .parallelStream().map(InstitutionTypeDO::getParentId).distinct().collect(Collectors.toList()), siteId);
        Map<String, InstitutionTypeDO> institutionTypeIdDOMap1 = institutionTypeList.parallelStream()
                .collect(Collectors.toMap(BaseDO::getId, v -> v));
        return institutionDOList.parallelStream().map(institutionDO -> {
            InstitutionListVO institutionListVO = institutionDO.to(InstitutionListVO.class);
            // 二级分类
            InstitutionTypeDO institutionTypeDO2 = institutionTypeIdDOMap2.get(institutionListVO.getInstitutionTypeId());
            if (institutionTypeDO2 == null) {
                return null;
            }
            institutionListVO.setSecondSort(institutionTypeDO2.getSort());
            InstitutionTypeDO institutionTypeDO1 = institutionTypeIdDOMap1.get(institutionTypeDO2.getParentId());
            if (institutionTypeDO1 == null) {
                return null;
            }
            institutionListVO.setFirstSort(institutionTypeDO1.getSort());
            return institutionListVO;
        }).filter(Objects::nonNull).sorted(Comparator.comparing(InstitutionListVO::getFirstSort)
                .thenComparing(InstitutionListVO::getSecondSort)).collect(Collectors.toList());
    }

    @Override
    public Page<InstitutionDO> selectByTypeIdAndCompanyId(String institutionTypeId, String companyId, Integer pageNo, Integer pageSize, String siteId) {
        InstitutionTypeDO institutionTypeDO = institutionTypeService.selectDOById(institutionTypeId, siteId);
        ParamException.notNull(institutionTypeDO, "分类信息不存在，请刷新后重试");
        if (institutionTypeDO.getLevel() == 1) {
            // 一级分类 先查二级分类
            List<InstitutionTypeDO> institutionTypeDOList = institutionTypeService
                    .selectDOByParentIds(Collections.singletonList(institutionTypeDO.getId()), siteId);
            if (CollectionUtils.isEmpty(institutionTypeDOList)) {
                return new Page<>(pageSize, pageNo);
            }
            // 二级分类查询分类下制度
            Example example = new Example(InstitutionDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", siteId)
                    .andEqualTo("companyId", companyId)
                    .andIn("institutionTypeId", institutionTypeDOList
                            .parallelStream().map(BaseDO::getId).collect(Collectors.toList()));
            example.orderBy("isOpen").desc().orderBy("gmtCreate").desc();
            return institutionDAO.selectPageByExample(example, pageNo, pageSize);
        } else if (institutionTypeDO.getLevel() == 2) {
            // 二级分类查询分类下制度
            Example example = new Example(InstitutionDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", siteId)
                    .andEqualTo("companyId", companyId)
                    .andEqualTo("institutionTypeId", institutionTypeId);
            example.orderBy("isOpen").desc().orderBy("gmtCreate").desc();
            return institutionDAO.selectPageByExample(example, pageNo, pageSize);
        } else {
            return new Page<>(pageSize, pageNo);
        }
    }

    @Override
    public List<InstitutionDO> selectByCompanyIdAndTitle(String companyId, String title, String siteId) {
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId)
                .andEqualTo("institutionTitle", title);
        return institutionDAO.selectByExample(example);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param institutionQuery 查询参数
     * @param siteId           所属站点id
     * @return example
     */
    private Example buildExample(InstitutionQuery institutionQuery, String siteId) {
        Example example = new Example(InstitutionDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (institutionQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", institutionQuery.getCompanyId());
        }
        // 排序
        ExampleKit.setExampleOrder(example, institutionQuery.getOrders());
        return example;
    }
}




